òɾۿûѧϰʹá
ԭַhttps://www.joinquant.com/post/13973

ԭһ˵ʽ鵽ԭĺ߽ۡ


ԭĲԴ£

#ԸROEΪɸѡ׼ѡ300ĹƱΪƱ
#CAPMģͣѡӻع飬ֵѡֵǰ16֧ƱͶ
import numpy as np
from scipy import stats
import pylab

'''
============================================================================
ʼ
============================================================================
'''

def initialize(context):
    set_params()        #1òԲ
    set_variables()     #2м
    set_backtest()    # 3ûز
    run_daily(stop, time='after_close')
    
#1òԲ
def set_params():
    g.index = '000300.XSHG'
    #ÿȡalphaС16֧Ʊ
    g.num = 16
    #ÿλعǰdays
    g.days = 121
    g.tc = 10
    g.N = 121          # Ҫǰ
    g.rf=0.04/252           #޷ʣڼ㳬
    g.ROE_requirement=10 #ROE10%
    
#2м
def set_variables():
    g.t=0               #¼ز
    g.if_trade=False    #Ƿ
    g.feasible_stocks=[]
    
#3ûز
def set_backtest():
    set_benchmark('000300.XSHG')
    set_option('use_real_price',True) # ʵ۸
    log.set_level('order','error')    # ñȼ
    
'''
=====================================================================
ÿزǰ
=====================================================================
'''
def before_trading_start(context):
    if g.t % g.tc ==0:
        #ÿg.tc죬һ
        g.if_trade=True 
        # 
        set_slip_fee(context) 
        
        
        # ROE趨ֵĹƱ
        a=query(indicator.code,indicator.roe
        # ɸѡ ROE趨ֵ
        ).filter(indicator.roe > g.ROE_requirement
        #  ROEӴС
        ).order_by(indicator.roe.desc()
        ).limit(1000)
        ROE_securities=get_fundamentals(a)
        securities_list=list(ROE_securities.code)


        g.feasible_stocks = set_feasible_stocks(securities_list,g.N,context)
    g.t+=1
    
#4 ޳ƱڼͣƵĹƱ
def set_feasible_stocks(stock_list,days,context):
    # õǷͣϢdataframeͣƵ1δͣƵ0
    suspened_info_df = get_price(list(stock_list), start_date=context.current_dt, end_date=context.current_dt, frequency='daily', fields='paused')['paused'].T
    # ͣƹƱ dataframe
    unsuspened_index = suspened_info_df.iloc[:,0]<1
    # õδͣƹƱĴlist:
    unsuspened_stocks = suspened_info_df[unsuspened_index].index
    # һɸѡǰdaysδͣƵĹƱlist:
    feasible_stocks=[]
    current_data=get_current_data()
    for stock in unsuspened_stocks:
        if not(isnan(attribute_history(stock, days, unit='1d',fields=('close'),skip_paused=True).iloc[0,0])):
            feasible_stocks.append(stock)
    return feasible_stocks    

#5 ݲͬʱΣû
def set_slip_fee(context):
    # Ϊ0
    set_slippage(FixedSlippage(0)) 
    # ݲͬʱ
    dt=context.current_dt
    log.info(type(context.current_dt))
    
    if dt>datetime.datetime(2013,1, 1):
        set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5)) 
        
    elif dt>datetime.datetime(2011,1, 1):
        set_commission(PerTrade(buy_cost=0.001, sell_cost=0.002, min_cost=5))
            
    elif dt>datetime.datetime(2009,1, 1):
        set_commission(PerTrade(buy_cost=0.002, sell_cost=0.003, min_cost=5))
                
    else:
        set_commission(PerTrade(buy_cost=0.003, sell_cost=0.004, min_cost=5))


'''
=====================================================================
ÿزʱ
=====================================================================
'''
def handle_data(context, data):
    to_sell, to_buy = get_signal(context)
    sell_and_buy_stocks(context, to_sell, to_buy)

#6 Ʊ۸תΪʣΪdaysĹƱ̼ۣΪdays-1ĳ
def price2ret(price):
    ret = []
    rf = g.rf
    for i in range(len(price)-1):
        ret.append((price[i+1] - price[i])/price[i] - rf)
    return ret

#7 õź
def get_signal(context):
    if g.if_trade == True:
        num = g.num
    #stocksΪROEɸѡĹƱlist
        stocks = g.feasible_stocks
    #ȡdaysյ
        days = g.days
    #securityΪ300ָ
        security = g.index
    #ȡû300ָ̼
        marketporfolio = attribute_history(security, days, '1d', 'close')
    #㻦300ָ
        marketreturn = price2ret(marketporfolio['close'])
        alpha=[]
    #forѭͨROEɸѡĹƱеÿƱalpha
        for stock in stocks:
            stockprice = attribute_history(stock, days, '1d', 'close')
            stockreturn = price2ret(stockprice['close'])
            beta, stockalpha, r_value, p_value, slope_std_error = stats.linregress(marketreturn, stockreturn)
            alpha.append([stock,stockalpha])
    #ÿֻƱalpha
        sortedalpha = sorted(alpha,key=lambda X:X[1])
    #ȡalphanum֧Ʊ
        targetstocks = sortedalpha[(-num):]
    #
        targetstock = []
        taralpha = []
    #forѭõĿƱĴͶӦalpha
        for k1 in range(len(targetstocks)):
            targetstock.append(targetstocks[k1][0])
            taralpha.append(targetstocks[k1][1])
        taralpha = [(max(taralpha) - p)/(max(taralpha) - min(taralpha)) for p in taralpha]
        totalalpha = sum(taralpha)
        
    #ÿƱĳֲȨأalpha
        weights = [x/totalalpha for x in taralpha]
    #õǰԳеĹƱ
        present = context.portfolio.positions
    #õǰƱеĹƱ
        stocksnow = present.keys()
   
        if len(stocksnow)>0:
            valuenow = []
            stockandvalue = {}
            for stock in stocksnow:
                s_amount = context.portfolio.positions[stock].sellable_amount
                l_s_p = context.portfolio.positions[stock].last_sale_price
                valuenow = s_amount*l_s_p
                stockandvalue[stock] = valuenow
    #õǰƱϺʣʽܺ
        capital = context.portfolio.portfolio_value
    #õĿȨʱӦĹƱ
        tarcapallocation = [capital*x for x in weights]
        tarstoandcap = dict(zip(targetstock, tarcapallocation))
        to_sell = {}
    #ǰйƱֵĿֵ
        for stock in stocksnow:
            if stock in targetstock:
                gap = tarstoandcap[stock] - stockandvalue[stock]
                if gap<0:
                    to_sell[stock] = tarstoandcap[stock]
            else:
                to_sell[stock] = 0
    
    #ĿȶĿƱϽ
        to_buy = {}
        for stock in targetstock:
            to_buy[stock] = tarstoandcap[stock]
        #print(to_sell, to_buy)
        return to_sell, to_buy
    else:
        return {},{}
        
#8 λ
def sell_and_buy_stocks(context, to_sell, to_buy):
    if g.if_trade:
        for stock in to_sell.keys():
            order_target_value(stock, to_sell[stock])
        for stock in to_buy.keys():
            order_target_value(stock, to_buy[stock])
    g.if_trade = False

#9 ֹ
def stop(context):
    # ѭ鿴ֲֵÿƱ
    for stock in context.portfolio.positions:
        # Ʊ̼۸ƽɱС0.7𳬹30%
        if (context.portfolio.positions[stock].price/context.portfolio.positions[stock].avg_cost < 0.7): 
            # stockĳֲΪ0
            order_target(stock, 0) 
            #ʣʽծ
            cash=context.portfolio.available_cash
            order_target_value('000012.XSHG',cash)
            # ־Ʊ ֹ
            print "\n%s ֹ" % stock
    

